React+ViteプロジェクトにStorybook(v7)を導入する
吉川@広島です。
フロントエンドはもっぱらReact+Viteで開発することが多いのですが、以前これにStorybook v6を導入しようとして挫折したことがありました。Viteに対応させたくbuilder-viteを使ったものの動作させることができず、しばらくViteファーストなStorybook AlternativeであるLadleユーザになっていました。
ところが最近になり「Storybook v7でそのあたり良くなってるよ!」という情報を各所で見聞きするようになりました。ということでReact+Vite+Storybookを試してみたいと思います。
環境
- react: 18.2.0
- react-dom: 18.2.0
- vite: 4.2.0
- typescript: 5.0.2
- @storybook/react: 7.0.6
- @storybook/react-vite: 7.0.7
- tailwindcss: 3.3.1
- postcss: 8.4.21
- clsx: 1.2.1
Reactプロジェクト構築
Vite CLIで新規プロジェクトをinitします。
npm create vite@latest sample-pj -- --template react-ts cd sample-pj
以降、sample-pjをworking directoryとします。
Storybookを導入
Viteビルド設定でStorybookを導入します。Storybook CLIのinitを叩きます。
npx sb init --builder=vite
そのままだと動かない点があったので、いくらか手を加えてそれぞれ以下のように設定しました。
// package.json { "name": "sample-pj", "version": "0.0.0", "private": true, "type": "module", "scripts": { "story:dev": "storybook dev -p 9009", }, "dependencies": { "react": "18.2.0", "react-dom": "18.2.0", }, "devDependencies": { "@types/react": "18.0.28", "@types/react-dom": "18.0.11", "@storybook/react": "7.0.6", "@storybook/react-vite": "7.0.7", "typescript": "5.0.2", "vite": "4.2.0" } }
// .storybook/main.ts import type { StorybookConfig } from "@storybook/react-vite"; const config: StorybookConfig = { stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"], addons: [], framework: { name: "@storybook/react-vite", options: {}, }, docs: { autodocs: "tag", }, }; export default config;
設定は以上です。
サンプルコンポーネントを作り、Storybookで描画してみる
では、次のようなInputコンポーネントを作ってみます。Tailwindでスタイリングしています。
// src/components/Input.tsx import clsx from "clsx"; import { type ComponentProps, type FC } from "react"; interface InputProps extends ComponentProps<"input"> {} export const Input: FC<InputProps> = ({ className, ...props }) => ( <input {...props} className={clsx( "w-full appearance-none rounded border px-3 py-2 leading-tight text-gray-700 shadow focus:outline-none", className )} /> );
これのストーリーファイルを作ります。
// src/components/Input.stories.tsx import type { Meta, StoryObj } from "@storybook/react"; import { Input } from "./Input"; const meta: Meta<typeof Input> = { title: "Input", component: Input, }; // eslint-disable-next-line import/no-default-export export default meta; type Story = StoryObj<typeof Input>; export const DefaultInput: Story = { render: () => <Input />, }; export const TypedInput: Story = { render: () => <Input value="てすと" />, };
Storybookのローカルサーバを起動します。
npm run story:dev
http://localhost:9009 にアクセスすると、Storybook上でInputコンポーネントを確認することができました。
というわけでStorybook+Viteを動かすことができました。
ハマった点
Storybook init直後の状態だと npm run story:dev
時に以下のエラーが発生しました。
[ERROR] No matching export in "global-externals:@storybook/core-events" for import "DOCS_PREPARED"
一旦 main.ts
から addons
の内容を除去することで解消しました。
// .storybook/main.ts addons: [ "@storybook/addon-links", // 除去 "@storybook/addon-essentials", // 除去 "@storybook/addon-interactions", // 除去 ]
これについては今後アドオンが必要になったタイミングで再度トライしてみようと思います。